package com.atguigu.item.service.impl;

import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.feign.product.ProductSkuDataFeign;
import com.atguigu.gmall.product.entity.SkuImage;
import com.atguigu.gmall.product.entity.SkuInfo;
import com.atguigu.gmall.product.entity.SpuSaleAttr;
import com.atguigu.gmall.product.vo.CategoryTreeVo;
import com.atguigu.gmall.product.vo.SkuDataVo;
import com.atguigu.gmall.starter.cache.aspect.annotation.MallCache;
import com.atguigu.gmall.starter.cache.service.CacheService;
import com.atguigu.item.service.SkuDataService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
@Service
public class SkuDataServiceImpl implements SkuDataService {
    @Autowired
    ProductSkuDataFeign skuDataFeign;
    @Autowired
    ThreadPoolExecutor coreExecutor;

    //缓存

    //缓存： O(1)
    //本地缓存： 缓存的数据就放在微服务所在的jvm内存中
    private Map<Long, SkuDataVo> cache = new ConcurrentHashMap<>();

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    CacheService cacheService;
    @Autowired
    RedissonClient  redissonClient ;

    /**
     * 增强切入
     * @param skuId
     * @return
     * @throws InterruptedException
     */
    @MallCache(bigMapName = RedisConst.SKUID_BITMAP,
            bigMapKey = "#{#args[0]}",
            ttl = 7,
            unit = TimeUnit.DAYS)
    @Override
    public SkuDataVo getSkuData(Long skuId) throws InterruptedException {
          return   getDataFromRpc(skuId);
        }
    //juc 本地锁  在分布式场景  会导致锁不住所有机器
    ReentrantLock lock = new ReentrantLock();//原理  aqs cas

   //    public SkuDataVo getSkuDataWithLocalList(Long skuId) {
//        //TODO 获取商品详情数据
//        SkuDataVo returnVal = null;
//        //TODO  1 先查缓存
//        log.info("商品详情查询开始...");
//        returnVal = cacheService.getFromCache(skuId);
//        if (returnVal == null) { //一定要能判定出 真没(null)和假没(x)
//            // 2、位图判定是否有
//            boolean contain = cacheService.mightContain(skuId);
//            if (!contain) {
//                log.info("bitmap没有，疑似攻击请求，直接打回");
//                return null;
//            }
//            //3、缓存中没有；回源
//            log.info("bitmap有，准备回源。需要加锁防止击穿");
//            //准备拦截击穿风险
//
//            boolean tryLock = lock.tryLock(); //100w进来瞬间进行抢锁；
//            if (tryLock) {
//                log.info("加锁成功...正在回源");
//                //4、抢锁成功
//                returnVal = getDataFromRpc(skuId);
//                //5、保存到缓存； null值缓存都可能不会被调用；
//                //如果这里用的是bloomfilter，可能会误判，即使误判，放给数据库没有也要null值缓存
//                cacheService.saveData(skuId, returnVal);
//                lock.unlock();
//            } else {
//                //6、抢锁失败，500ms 后直接看缓存即可。
//                try {
//                    log.info("加锁失败...稍等直接返回缓存数据");
//                    TimeUnit.MILLISECONDS.sleep(500);
//                    returnVal = cacheService.getFromCache(skuId);
//                } catch (InterruptedException e) {
//                }
//            }
//        }
//        return returnVal;
//    }

//    public SkuDataVo getSkuDetailDataNullSave(Long skuId) {
//        //1、先查缓存   sku:info:49 == 商品json
//        String json = redisTemplate.opsForValue().get("sku:info:" + skuId);
//        if (StringUtils.isEmpty(json)) {
//            //2、缓存没有，回源。
//            synchronized (this) {
//                //先看缓存
//                SkuDataVo result = getDataFromRpc(skuId);
//                String jsonData = "x";
//                //3、放入缓存； 即使是null值也缓存到redis
//                if (result != null) {
//                    jsonData = JSON.toJSONString(result); // {}
//                }
//                redisTemplate.opsForValue().set("sku:info:" + skuId, jsonData, 7, TimeUnit.DAYS);
//
//                return result;
//            }
//
//        }
//
//        //4、缓存中有；
//        //1）、真有：  json真数据
//        //2）、假有：  x
//        if ("x".equals(json)) {
//            log.info("疑似攻击请求");
//            return null;
//        }
//        SkuDataVo result = JSON.parseObject(json, SkuDataVo.class);
//        return result;
//    }

    /**
     * 查询商品详情
     *
     * @param skuId
     * @return
     */
    public SkuDataVo getSkuDetailDataLocalCache(Long skuId) {

        //1、先查缓存
        SkuDataVo result = cache.get(skuId);
        //2、缓存中没有
        if (result == null) {
            log.info("商品详情：缓存未命中，正在回源");
            //3、回源：  回到数据源头进行查询
            result = getDataFromRpc(skuId);
            //4、把数据同步到缓存
            cache.put(skuId, result);
        } else {
            log.info("商品详情：缓存命中");
        }

        return result;
    }

    private SkuDataVo getDataFromRpc(Long skuId) {
        SkuDataVo skuDataVo = new SkuDataVo();
        //1商品详情 图片
        //1异步自定义线程池
        CompletableFuture<SkuInfo> skuInfoFuture = CompletableFuture.supplyAsync(() -> {
            log.info("商品详情数据");
            SkuInfo skuInfo = skuDataFeign.getSkuInfo(skuId).getData();
            return skuInfo;
        }, coreExecutor);

        //2 图片异步
        CompletableFuture<Void> imageFuture = skuInfoFuture.thenAcceptAsync((res) -> {
            log.info("图片详情");
            List<SkuImage> images = skuDataFeign.getImages(skuId).getData();
            res.setSkuImageList(images);
            skuDataVo.setSkuInfo(res);
        }, coreExecutor);


        //TODO 2 异步 当前商品的精准完整分类信息
        CompletableFuture<Void> categoryFuture = skuInfoFuture.thenAcceptAsync((res) -> {
            CategoryTreeVo categoryTreeVo = skuDataFeign.getCategoryTreeWithC3Id(res.getCategory3Id()).getData();
            SkuDataVo.CategoryViewDTO viewDTO = new SkuDataVo.CategoryViewDTO();
            viewDTO.setCategory1Id(categoryTreeVo.getCategoryId());
            viewDTO.setCategory1Name(categoryTreeVo.getCategoryName());

            CategoryTreeVo treeVo = categoryTreeVo.getCategoryChild().get(0);
            viewDTO.setCategory2Id(treeVo.getCategoryId());
            viewDTO.setCategory2Name(treeVo.getCategoryName());

            CategoryTreeVo vo = treeVo.getCategoryChild().get(0);
            viewDTO.setCategory3Id(vo.getCategoryId());
            viewDTO.setCategory3Name(vo.getCategoryName());

            skuDataVo.setCategoryView(viewDTO);

        }, coreExecutor);

        //3 TODO 异步：实时价格
        CompletableFuture<Void> priceFuture = CompletableFuture.runAsync(() -> {
            log.info("价格price");
            BigDecimal data = skuDataFeign.getPrice(skuId).getData();
            skuDataVo.setPrice(data);
        });

        //TODO 销售属性
        CompletableFuture<Void> saleAttrFuture = skuInfoFuture.thenAcceptAsync(res -> {
            log.info("销售属性");
            List<SpuSaleAttr> spuSaleAttrs = skuDataFeign.getSpuSaleAttr(res.getSpuId(), skuId).getData();
            skuDataVo.setSpuSaleAttrList(spuSaleAttrs);
        }, coreExecutor);


        //6、当前sku的所有兄弟们的所有组合可能性。
        CompletableFuture<Void> valueJsonFuture = skuInfoFuture.thenAcceptAsync((res) -> {
            String json = skuDataFeign.getValueSkuJson(res.getSpuId()).getData();
            skuDataVo.setValuesSkuJson(json);
        }, coreExecutor);

        //等所有任务执行完成以后 再执行这个任务
        CompletableFuture.allOf(valueJsonFuture, saleAttrFuture, priceFuture, categoryFuture, imageFuture).join();
        return skuDataVo;
    }


}

